package com.activeharmony;

/*
 * Copyright (C) 2010 Michael Pardo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.activeharmony.serializer.TypeSerializer;
import com.activeharmony.util.Log;

import ohos.app.Context;

import java.util.Collection;

import net.sqlcipher.database.SQLiteDatabase;

import ohos.utils.LruBuffer;

/**
 * class Cache
 */
public final class Cache {
    // ////////////////////////////////////////////////////////////////////////////////////
    // PUBLIC CONSTANTS
    // ////////////////////////////////////////////////////////////////////////////////////

    /**
    * DEFAULT_CACHE_SIZE cache size
    */
    public static final int DEFAULT_CACHE_SIZE = 1024;

    // ////////////////////////////////////////////////////////////////////////////////////
    // PRIVATE MEMBERS
    // ////////////////////////////////////////////////////////////////////////////////////

    private static Context sContext;

    private static ModelInfo sModelInfo;
    private static DatabaseHelper sDatabaseHelper;

    private static LruBuffer<String, Model> sEntities;

    private static boolean sIsInitialized = false;

    // ////////////////////////////////////////////////////////////////////////////////////
    // CONSTRUCTORS
    // ////////////////////////////////////////////////////////////////////////////////////

    private Cache() {
    }

    // ////////////////////////////////////////////////////////////////////////////////////
    // PUBLIC METHODS
    // ////////////////////////////////////////////////////////////////////////////////////

    /**
    * method initialize
    *
    * @param configuration configuration
    */
    public static synchronized void initialize(Configuration configuration) {
        if (sIsInitialized) {
            Log.i("activeharmony already initialized.");
            return;
        }

        sContext = configuration.getContext();
        sModelInfo = new ModelInfo(configuration);
        sDatabaseHelper = new DatabaseHelper(configuration);

        // It would be nice to override sizeOf here and calculate the memory
        // actually used, however at this point it seems like the reflection
        // required would be too costly to be of any benefit. We'll just set a max
        // object size instead.
        sEntities = new LruBuffer<String, Model>(configuration.getCacheSize());

        openDatabase();

        sIsInitialized = true;

        Log.i("activeharmony initialized successfully.");
    }

    /**
    * method clear
    */
    public static synchronized void clear() {
        sEntities.clear();
        Log.i("Cache cleared.");
    }

    /**
    * method dispose
    */
    public static synchronized void dispose() {
        closeDatabase();

        sEntities = null;
        sModelInfo = null;
        sDatabaseHelper = null;

        sIsInitialized = false;

        Log.i("ActiveHarmony disposed. Call initialize to use library.");
    }

    /**
    * method isInitialized
    *
    * @return sIsInitialized boolean
    */
    public static boolean isInitialized() {
        return sIsInitialized;
    }

    /**
    * method openDatabase
    *
    * @return SQLiteDatabase SQLiteDatabase
    */
    public static synchronized SQLiteDatabase openDatabase() {
        return sDatabaseHelper.getWritableDatabase("");
    }

    /**
    * method closeDatabase
    */
    public static synchronized void closeDatabase() {
        sDatabaseHelper.close();
    }

    /**
    * method getContext
    *
    * @return Context Context
    */
    public static Context getContext() {
        return sContext;
    }

    /**
    * method getIdentifier
    *
    * @param type type
    * @param id id
    * @return String identifier
    */
    public static String getIdentifier(Class<? extends Model> type, Long id) {
        return getTableName(type) + "@" + id;
    }

    /**
    * method getIdentifier
    *
    * @param entity entity
    * @return String identifier
    */
    public static String getIdentifier(Model entity) {
        return getIdentifier(entity.getClass(), entity.getId());
    }

    /**
    * method addEntity
    *
    * @param entity entity
    */
    public static synchronized void addEntity(Model entity) {
        sEntities.put(getIdentifier(entity), entity);
    }

    /**
    * method getEntity
    *
    * @param type type
    * @param id id
    * @return Model Model
    */
    public static synchronized Model getEntity(Class<? extends Model> type, long id) {
        return sEntities.get(getIdentifier(type, id));
    }

    /**
    * method removeEntity
    *
    * @param entity entity
    */
    public static synchronized void removeEntity(Model entity) {
        sEntities.remove(getIdentifier(entity));
    }

    /**
    * method getTableInfos
    *
    * @return Collection<TableInfo>
    */
    public static synchronized Collection<TableInfo> getTableInfos() {
        return sModelInfo.getTableInfos();
    }

    /**
    * method getTableInfo
    *
    * @param type type
    * @return TableInfo TableInfo
    */
    public static synchronized TableInfo getTableInfo(Class<? extends Model> type) {
        return sModelInfo.getTableInfo(type);
    }

    /**
    * method getParserForType
    *
    * @param type type
    * @return TypeSerializer TypeSerializer
    */
    public static synchronized TypeSerializer getParserForType(Class<?> type) {
        return sModelInfo.getTypeSerializer(type);
    }

    /**
    * method String
    *
    * @param type type
    * @return table name
    */
    public static synchronized String getTableName(Class<? extends Model> type) {
        return sModelInfo.getTableInfo(type).getTableName();
    }
}
